package com.app.util.args;

import java.io.File;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.app.util.string.StringUtil;


public class ArgsValidater {

	Map<String, ValueValidater> options = new LinkedHashMap<String, ValueValidater>();
	Map<Integer, ValueValidater> args = new LinkedHashMap<Integer, ValueValidater>();

	public enum ArgType {
		Number, ExistsFile, CanWriteFile, String
	}

	public void addOption(String name, ArgType type, boolean notEmpty, String description) {
		options.put(name, new ValueValidater(name, type, notEmpty, description));
	}
 
	public void addOption(String name, ArgType type, String description) {
		addOption(name, type, false, description);
	}

	public void addArgs(ArgType type, boolean notEmpty, String description) {
		if (notEmpty) {
			for (Entry<Integer, ValueValidater> ent : this.args.entrySet()) {
				ValueValidater validater = ent.getValue();
				if (!validater.notEmpty) {
					throw new RuntimeException("不能在可空参数后设置非空参数检查");
				}
			}
		}
		args.put(args.size(), new ValueValidater(args.size(), type, notEmpty, description));
	}

	public void addArgs(ArgType type, String description) {
		addArgs(type, true, description);
	}

	public ValidateResult check(Args args) {
		for (Entry<Integer, ValueValidater> ent : this.args.entrySet()) {
			Integer i = ent.getKey();
			String value = args.getArg(i);
			ValueValidater validater = ent.getValue();
			if (!validater.check(value)) {
				return new ValidateResult(false, "Invalid Arg: " + validater.toString());
			}
		}
		for (Entry<String, ValueValidater> ent : options.entrySet()) {
			String name = ent.getKey();
			String value = args.getOptionValue(name);
			ValueValidater validater = ent.getValue();
			if (!validater.check(value)) {
				return new ValidateResult(false, "Invalid Option: " + validater.toString());
			}
		}
		return new ValidateResult(true, "");
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("Args: ").append("\n");
		for (Entry<Integer, ValueValidater> ent : args.entrySet()) {
			ValueValidater validater = ent.getValue();
			sb.append("  ").append(validater).append("\n");
		}
		sb.append("Options: ").append("\n");
		for (Entry<String, ValueValidater> ent : options.entrySet()) {
			ValueValidater validater = ent.getValue();
			sb.append("  ").append(validater).append("\n");
		}
		return sb.toString();
	}

	private class ValueValidater {

		private Object key;
		private ArgType type;
		private boolean notEmpty;
		private String description;

		public ValueValidater(Object key, ArgType type, boolean notEmpty, String description) {
			this.key = key;
			this.type = type;
			this.notEmpty = notEmpty;
			this.description = description;
		}

		private boolean check(String value) {
			if (StringUtil.isTrimEmpty(value)) {
				return !(notEmpty);
			}
			if (type == ArgType.ExistsFile) {
				try {
					return new File(value).exists();
				} catch (Exception ex) {
					return false;
				}
			} else if (type == ArgType.CanWriteFile) {
				try {
					return new File(value).canWrite();
				} catch (Exception ex) {
					return false;
				}
			} else if (type == ArgType.Number) {
				try {
					return null != new BigDecimal(value);
				} catch (Exception ex) {
					return false;
				}
			}
			return true;
		}

		public String toString() {
			if (key instanceof String) {
				if (notEmpty) {
					return "<" + key + "=" + type + "> #" + description;
				} else {
					return "[" + key + "=" + type + "] #" + description;
				}
			} else {
				if (notEmpty) {
					return key + ".<" + type + "> #" + description;
				} else {
					return key + ".[" + type + "] #" + description;
				}
			}
		}
	}
}
